package cn.kgc.shiro02.shiro;

import cn.kgc.shiro02.entity.*;
import cn.kgc.shiro02.mapper.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: 课工场
 * @Version: v1.0  2023/4/1
 * @Description:  自定义realm
 */
public class CustomerRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;


    @Autowired
    private RolePersMapper rolePersMapper;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("==============doGetAuthorizationInfo==================");
        // 用户名
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //TODO 根据用户名 查询用户角色信息  用户表  角色表  用户角色关联表

        // 1. 根据用户名 查询用户id
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername,primaryPrincipal);
        User user = userMapper.selectOne(lambda);
        Integer userId = user.getId();

        // 2.根据用户id  查询用户角色关联表 查询用户具有的角色id
        LambdaQueryWrapper<UserRole> lambda1 = new QueryWrapper<UserRole>().lambda();
        lambda1.eq(UserRole::getUserId,userId);
        List<UserRole> userRoles = userRoleMapper.selectList(lambda1);
        // stream流
        List<Integer> roleIds = userRoles.stream().map(userRole -> userRole.getRoleId()).collect(Collectors.toList());

        // 3.根据角色id 查询角色表
        List<Role> roles = roleMapper.selectBatchIds(roleIds);
        List<String> roleNames = roles.stream().map(role -> role.getRoleName()).collect(Collectors.toList());

        // 4.角色授权
        simpleAuthorizationInfo.addRoles(roleNames);

        //5.基于权限字符串授权
        LambdaQueryWrapper<RolePers> lambda2 = new QueryWrapper<RolePers>().lambda();

        //根据权限 角色id 查询权限id
        lambda2.in(RolePers::getRoleId,roleIds);

        List<RolePers> rolePers = rolePersMapper.selectList(lambda2);
        //{1,2,2}
        List<Integer> perIds = rolePers.stream().map(rp -> rp.getPerId()).collect(Collectors.toList());

        List<Permission> permissions = permissionMapper.selectBatchIds(perIds);

        // 获取所有的权限字符串
        List<String> strPermissions = permissions.stream().map(permission -> permission.getPermission()).collect(Collectors.toList());

        // 基于权限字符串授权
        simpleAuthorizationInfo.addStringPermissions(strPermissions);

        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("==============doGetAuthenticationInfo==================");
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        // TODO 根据用户名查询数据库
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername,username);
        User user = userMapper.selectOne(lambda);

        if(user!=null){
            if(user.getState()==0){   // 账号被禁用
                throw  new LockedAccountException();
            }
            NewByteSource newByteSource = new NewByteSource(user.getSalt());
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),
                    user.getPassword(), newByteSource, this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}
